/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2010 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef __SPELL_H
#define __SPELL_H

#include "GridDefines.h"
#include "SharedDefines.h"
#include "ObjectMgr.h"

class Unit;
class Player;
class GameObject;
class DynamicObject;
class WorldObject;
class Aura;
class SpellScript;
class ByteBuffer;

struct SpellEntry;

enum SpellCastTargetFlags
{
    TARGET_FLAG_SELF = 0x00000000, TARGET_FLAG_UNUSED1 = 0x00000001,          // not used in any spells as of 3.2.2a (can be set dynamically)
    TARGET_FLAG_UNIT = 0x00000002,          // pguid
    TARGET_FLAG_UNUSED2 = 0x00000004,          // not used in any spells as of 3.2.2a (can be set dynamically)
    TARGET_FLAG_UNUSED3 = 0x00000008,          // not used in any spells as of 3.2.2a (can be set dynamically)
    TARGET_FLAG_ITEM = 0x00000010,          // pguid
    TARGET_FLAG_SOURCE_LOCATION = 0x00000020,          // 3 float
    TARGET_FLAG_DEST_LOCATION = 0x00000040,          // 3 float
    TARGET_FLAG_OBJECT_CASTER = 0x00000080,          // used in 7 spells only
    TARGET_FLAG_UNIT_CASTER = 0x00000100,          // looks like self target (480 spells)
    TARGET_FLAG_PVP_CORPSE = 0x00000200,          // pguid
    TARGET_FLAG_UNIT_CORPSE = 0x00000400,          // 10 spells (gathering professions)
    TARGET_FLAG_OBJECT = 0x00000800,          // pguid, 2 spells
    TARGET_FLAG_TRADE_ITEM = 0x00001000,          // pguid, 0 spells
    TARGET_FLAG_STRING = 0x00002000,          // string, 0 spells
    TARGET_FLAG_OPEN_LOCK = 0x00004000,          // 199 spells, opening object/lock
    TARGET_FLAG_CORPSE = 0x00008000,          // pguid, resurrection spells
    TARGET_FLAG_UNK17 = 0x00010000,          // pguid, not used in any spells as of 3.2.2a (can be set dynamically)
    TARGET_FLAG_GLYPH = 0x00020000,          // used in glyph spells
    TARGET_FLAG_UNK19 = 0x00040000,          //
    TARGET_FLAG_UNUSED20 = 0x00080000
// uint32 counter, loop { vec3 - screen position (?), guid }, not used so far
};
#define MAX_TARGET_FLAGS 21

enum SpellCastFlags
{
    CAST_FLAG_NONE = 0x00000000, CAST_FLAG_PENDING = 0x00000001,          // Pending == 1
    CAST_FLAG_UNKNOWN_2 = 0x00000002, CAST_FLAG_UNKNOWN_3 = 0x00000004, CAST_FLAG_UNKNOWN_4 = 0x00000008, CAST_FLAG_UNKNOWN_5 = 0x00000010, CAST_FLAG_AMMO = 0x00000020,          // Projectiles visual
    CAST_FLAG_UNKNOWN_7 = 0x00000040, CAST_FLAG_UNKNOWN_8 = 0x00000080, CAST_FLAG_UNKNOWN_9 = 0x00000100, CAST_FLAG_UNKNOWN_10 = 0x00000200, CAST_FLAG_UNKNOWN_11 = 0x00000400, CAST_FLAG_POWER_LEFT_SELF = 0x00000800, CAST_FLAG_UNKNOWN_13 = 0x00001000, CAST_FLAG_UNKNOWN_14 = 0x00002000, CAST_FLAG_UNKNOWN_15 = 0x00004000, CAST_FLAG_UNKNOWN_16 = 0x00008000, CAST_FLAG_UNKNOWN_17 = 0x00010000, CAST_FLAG_UNKNOWN_18 = 0x00020000, CAST_FLAG_UNKNOWN_19 = 0x00040000, CAST_FLAG_UNKNOWN_20 = 0x00080000, CAST_FLAG_UNKNOWN_21 = 0x00100000, CAST_FLAG_RUNE_LIST = 0x00200000, CAST_FLAG_UNKNOWN_23 = 0x00400000, CAST_FLAG_UNKNOWN_24 = 0x00800000, CAST_FLAG_UNKNOWN_25 = 0x01000000, CAST_FLAG_UNKNOWN_26 = 0x02000000, CAST_FLAG_UNKNOWN_27 = 0x04000000, CAST_FLAG_UNKNOWN_28 = 0x08000000, CAST_FLAG_UNKNOWN_29 = 0x10000000, CAST_FLAG_UNKNOWN_30 = 0x20000000, CAST_FLAG_UNKNOWN_31 = 0x40000000, CAST_FLAG_UNKNOWN_32 = 0x80000000,
};

enum SpellRangeFlag
{
    SPELL_RANGE_DEFAULT = 0, SPELL_RANGE_MELEE = 1,          //melee
    SPELL_RANGE_RANGED = 2,          //hunter range and ranged weapon
};

enum SpellNotifyPushType
{
    PUSH_NONE = 0, PUSH_IN_FRONT, PUSH_IN_BACK, PUSH_IN_LINE, PUSH_IN_THIN_LINE, PUSH_SRC_CENTER, PUSH_DST_CENTER, PUSH_CASTER_CENTER,          //this is never used in grid search
    PUSH_CHAIN,
};

enum SpellLogType
{
    SPELL_LOG_NON_MELEE_DAMAGE = 29868, SPELL_LOG_EXECUTE = 46824, SPELL_LOG_ENERGIZE = 61676, SPELL_LOG_HEAL = 28292, SPELL_LOG_MISS = 48548, SPELL_LOG_PERIODIC_AURA = 13192, SPELL_LOG_REMOVE_1 = 0xED7E,          // currently unused (not updated even)
    SPELL_LOG_REMOVE_2 = 0x9F74,          // currently unused (n/u)
    SPELL_LOG_REMOVE_3 = 0xD557,
// currently unused (n/u)
};
bool IsQuestTameSpell (uint32 spellId);

namespace Trinity
{
    struct SpellNotifierCreatureAndPlayer;
}

typedef std::list<Unit*> UnitList;

class SpellCastTargets
{
public:
    SpellCastTargets ();
    ~SpellCastTargets ();

    SpellCastTargets& operator= (const SpellCastTargets &target)
    {
        m_unitTarget = target.m_unitTarget;
        m_itemTarget = target.m_itemTarget;
        m_GOTarget = target.m_GOTarget;

        m_unitTargetGUID = target.m_unitTargetGUID;
        m_GOTargetGUID = target.m_GOTargetGUID;
        m_CorpseTargetGUID = target.m_CorpseTargetGUID;
        m_itemTargetGUID = target.m_itemTargetGUID;

        m_itemTargetEntry = target.m_itemTargetEntry;

        m_srcTransGUID = target.m_srcTransGUID;
        m_srcTransOffset = target.m_srcTransOffset;
        m_srcPos = target.m_srcPos;

        m_dstTransGUID = target.m_dstTransGUID;
        m_dstTransOffset = target.m_dstTransOffset;
        m_dstPos = target.m_dstPos;

        m_elevation = target.m_elevation;
        m_speed = target.m_speed;

        m_strTarget = target.m_strTarget;

        m_targetMask = target.m_targetMask;

        return *this;
    }
    void read (ByteBuffer & data, Unit * caster);
    void write (ByteBuffer & data);

    uint32 getTargetMask () const
    {
        return m_targetMask;
    }
    void setTargetMask (uint32 newMask)
    {
        m_targetMask = newMask;
    }

    uint64 getUnitTargetGUID () const
    {
        return m_unitTargetGUID;
    }
    Unit *getUnitTarget () const
    {
        return m_unitTarget;
    }
    void setUnitTarget (Unit *target);
    void setSrc (float x, float y, float z);
    void setSrc (Position &pos);
    void setSrc (WorldObject &wObj);
    void modSrc (Position &pos);
    void setDst (float x, float y, float z, float orientation, uint32 mapId = MAPID_INVALID);
    void setDst (Position &pos);
    void SetDst (Position const& pos);
    void setDst (WorldObject &wObj);
    void setDst (SpellCastTargets &spellTargets);
    void modDst (Position &pos);

    uint64 getGOTargetGUID () const
    {
        return m_GOTargetGUID;
    }
    GameObject *getGOTarget () const
    {
        return m_GOTarget;
    }
    void setGOTarget (GameObject *target);

    uint64 getCorpseTargetGUID () const
    {
        return m_CorpseTargetGUID;
    }
    void setCorpseTarget (Corpse* corpse);
    uint64 getItemTargetGUID () const
    {
        return m_itemTargetGUID;
    }
    Item* getItemTarget () const
    {
        return m_itemTarget;
    }
    uint32 getItemTargetEntry () const
    {
        return m_itemTargetEntry;
    }
    void setItemTarget (Item* item);
    void setTradeItemTarget (Player* caster);
    void updateTradeSlotItem ()
    {
        if (m_itemTarget && (m_targetMask & TARGET_FLAG_TRADE_ITEM))
        {
            m_itemTargetGUID = m_itemTarget->GetGUID();
            m_itemTargetEntry = m_itemTarget->GetEntry();
        }
    }

    bool IsEmpty () const
    {
        return m_GOTargetGUID == 0 && m_unitTargetGUID == 0 && m_itemTarget == 0 && m_CorpseTargetGUID == 0;
    }
    bool HasSrc () const
    {
        return getTargetMask() & TARGET_FLAG_SOURCE_LOCATION;
    }
    bool HasDst () const
    {
        return getTargetMask() & TARGET_FLAG_DEST_LOCATION;
    }
    bool HasTraj () const
    {
        return m_speed != 0;
    }

    float GetDist2d () const
    {
        return m_srcPos.GetExactDist2d(&m_dstPos);
    }
    float GetSpeedXY () const
    {
        return m_speed * cos(m_elevation);
    }
    float GetSpeedZ () const
    {
        return m_speed * sin(m_elevation);
    }

    void Update (Unit* caster);
    void OutDebug ();

    uint64 m_srcTransGUID;
    Position m_srcTransOffset;
    Position m_srcPos;
    uint64 m_dstTransGUID;
    Position m_dstTransOffset;
    WorldLocation m_dstPos;
    float m_elevation, m_speed;
    std::string m_strTarget;

private:
    uint32 m_targetMask;
    // objects (can be used at spell creating and after Update at casting
    Unit *m_unitTarget;
    GameObject *m_GOTarget;
    Item *m_itemTarget;

    // object GUID/etc, can be used always
    uint64 m_unitTargetGUID;
    uint64 m_GOTargetGUID;
    uint64 m_CorpseTargetGUID;
    uint64 m_itemTargetGUID;
    uint32 m_itemTargetEntry;
};

struct SpellValue
{
    explicit SpellValue (SpellEntry const *proto)
    {
        for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
            EffectBasePoints[i] = proto->EffectBasePoints[i];
        MaxAffectedTargets = proto->MaxAffectedTargets;
        RadiusMod = 1.0f;
    }
    int32 EffectBasePoints[3];
    uint32 MaxAffectedTargets;
    float RadiusMod;
    uint8 AuraStackAmount;
};

enum SpellState
{
    SPELL_STATE_NULL = 0, SPELL_STATE_PREPARING = 1, SPELL_STATE_CASTING = 2, SPELL_STATE_FINISHED = 3, SPELL_STATE_IDLE = 4, SPELL_STATE_DELAYED = 5
};

// TODO
enum SpellEffectHandleMode
{
    SPELL_EFFECT_HANDLE_LAUNCH, SPELL_EFFECT_HANDLE_LAUNCH_TARGET, SPELL_EFFECT_HANDLE_HIT, SPELL_EFFECT_HANDLE_HIT_TARGET,
};

enum ReplenishType
{
    REPLENISH_UNDEFINED = 0, REPLENISH_HEALTH = 20, REPLENISH_MANA = 21, REPLENISH_RAGE = 22
};

enum SpellTargets
{
    SPELL_TARGETS_NONE = 0, SPELL_TARGETS_ALLY, SPELL_TARGETS_ENEMY, SPELL_TARGETS_ENTRY, SPELL_TARGETS_CHAINHEAL, SPELL_TARGETS_ANY, SPELL_TARGETS_GO
};

class Spell
{
    friend struct Trinity::SpellNotifierCreatureAndPlayer;
    friend void Unit::SetCurrentCastedSpell (Spell * pSpell);
    friend class SpellScript;
public:

    void EffectNULL (SpellEffIndex effIndex);
    void EffectUnused (SpellEffIndex effIndex);
    void EffectDistract (SpellEffIndex effIndex);
    void EffectPull (SpellEffIndex effIndex);
    void EffectSchoolDMG (SpellEffIndex effIndex);
    void EffectEnvirinmentalDMG (SpellEffIndex effIndex);
    void EffectInstaKill (SpellEffIndex effIndex);
    void EffectDummy (SpellEffIndex effIndex);
    void EffectTeleportUnits (SpellEffIndex effIndex);
    void EffectApplyAura (SpellEffIndex effIndex);
    void EffectSendEvent (SpellEffIndex effIndex);
    void EffectPowerBurn (SpellEffIndex effIndex);
    void EffectPowerDrain (SpellEffIndex effIndex);
    void EffectHeal (SpellEffIndex effIndex);
    void EffectBind (SpellEffIndex effIndex);
    void EffectHealthLeech (SpellEffIndex effIndex);
    void EffectQuestComplete (SpellEffIndex effIndex);
    void EffectCreateItem (SpellEffIndex effIndex);
    void EffectCreateItem2 (SpellEffIndex effIndex);
    void EffectCreateRandomItem (SpellEffIndex effIndex);
    void EffectPersistentAA (SpellEffIndex effIndex);
    void EffectEnergize (SpellEffIndex effIndex);
    void EffectOpenLock (SpellEffIndex effIndex);
    void EffectSummonChangeItem (SpellEffIndex effIndex);
    void EffectProficiency (SpellEffIndex effIndex);
    void EffectApplyAreaAura (SpellEffIndex effIndex);
    void EffectSummonType (SpellEffIndex effIndex);
    void EffectLearnSpell (SpellEffIndex effIndex);
    void EffectDispel (SpellEffIndex effIndex);
    void EffectDualWield (SpellEffIndex effIndex);
    void EffectPickPocket (SpellEffIndex effIndex);
    void EffectAddFarsight (SpellEffIndex effIndex);
    void EffectUntrainTalents (SpellEffIndex effIndex);
    void EffectHealMechanical (SpellEffIndex effIndex);
    void EffectJump (SpellEffIndex effIndex);
    void EffectJumpDest (SpellEffIndex effIndex);
    void EffectLeapBack (SpellEffIndex effIndex);
    void EffectQuestClear (SpellEffIndex effIndex);
    void EffectTeleUnitsFaceCaster (SpellEffIndex effIndex);
    void EffectLearnSkill (SpellEffIndex effIndex);
    void EffectAddHonor (SpellEffIndex effIndex);
    void EffectTradeSkill (SpellEffIndex effIndex);
    void EffectEnchantItemPerm (SpellEffIndex effIndex);
    void EffectEnchantItemTmp (SpellEffIndex effIndex);
    void EffectTameCreature (SpellEffIndex effIndex);
    void EffectSummonPet (SpellEffIndex effIndex);
    void EffectLearnPetSpell (SpellEffIndex effIndex);
    void EffectWeaponDmg (SpellEffIndex effIndex);
    void EffectForceCast (SpellEffIndex effIndex);
    void EffectForceCastWithValue (SpellEffIndex effIndex);
    void EffectTriggerSpell (SpellEffIndex effIndex);
    void EffectTriggerMissileSpell (SpellEffIndex effIndex);
    void EffectThreat (SpellEffIndex effIndex);
    void EffectHealMaxHealth (SpellEffIndex effIndex);
    void EffectInterruptCast (SpellEffIndex effIndex);
    void EffectSummonObjectWild (SpellEffIndex effIndex);
    void EffectScriptEffect (SpellEffIndex effIndex);
    void EffectSanctuary (SpellEffIndex effIndex);
    void EffectAddComboPoints (SpellEffIndex effIndex);
    void EffectDuel (SpellEffIndex effIndex);
    void EffectStuck (SpellEffIndex effIndex);
    void EffectSummonPlayer (SpellEffIndex effIndex);
    void EffectActivateObject (SpellEffIndex effIndex);
    void EffectApplyGlyph (SpellEffIndex effIndex);
    void EffectEnchantHeldItem (SpellEffIndex effIndex);
    void EffectSummonObject (SpellEffIndex effIndex);
    void EffectResurrect (SpellEffIndex effIndex);
    void EffectParry (SpellEffIndex effIndex);
    void EffectBlock (SpellEffIndex effIndex);
    void EffectLeap (SpellEffIndex effIndex);
    void EffectTransmitted (SpellEffIndex effIndex);
    void EffectDisEnchant (SpellEffIndex effIndex);
    void EffectInebriate (SpellEffIndex effIndex);
    void EffectFeedPet (SpellEffIndex effIndex);
    void EffectDismissPet (SpellEffIndex effIndex);
    void EffectReputation (SpellEffIndex effIndex);
    void EffectForceDeselect (SpellEffIndex effIndex);
    void EffectSelfResurrect (SpellEffIndex effIndex);
    void EffectSkinning (SpellEffIndex effIndex);
    void EffectCharge (SpellEffIndex effIndex);
    void EffectChargeDest (SpellEffIndex effIndex);
    void EffectProspecting (SpellEffIndex effIndex);
    void EffectMilling (SpellEffIndex effIndex);
    void EffectRenamePet (SpellEffIndex effIndex);
    void EffectSendTaxi (SpellEffIndex effIndex);
    void EffectSummonCritter (SpellEffIndex effIndex);
    void EffectKnockBack (SpellEffIndex effIndex);
    void EffectPullTowards (SpellEffIndex effIndex);
    void EffectDispelMechanic (SpellEffIndex effIndex);
    void EffectSummonDeadPet (SpellEffIndex effIndex);
    void EffectDestroyAllTotems (SpellEffIndex effIndex);
    void EffectDurabilityDamage (SpellEffIndex effIndex);
    void EffectSkill (SpellEffIndex effIndex);
    void EffectTaunt (SpellEffIndex effIndex);
    void EffectDurabilityDamagePCT (SpellEffIndex effIndex);
    void EffectModifyThreatPercent (SpellEffIndex effIndex);
    void EffectResurrectNew (SpellEffIndex effIndex);
    void EffectAddExtraAttacks (SpellEffIndex effIndex);
    void EffectSpiritHeal (SpellEffIndex effIndex);
    void EffectSkinPlayerCorpse (SpellEffIndex effIndex);
    void EffectStealBeneficialBuff (SpellEffIndex effIndex);
    void EffectUnlearnSpecialization (SpellEffIndex effIndex);
    void EffectHealPct (SpellEffIndex effIndex);
    void EffectEnergizePct (SpellEffIndex effIndex);
    void EffectTriggerSpellWithValue (SpellEffIndex effIndex);
    void EffectTriggerRitualOfSummoning (SpellEffIndex effIndex);
    void EffectKillCreditPersonal (SpellEffIndex effIndex);
    void EffectKillCredit (SpellEffIndex effIndex);
    void EffectQuestFail (SpellEffIndex effIndex);
    void EffectQuestStart (SpellEffIndex effIndex);
    void EffectRedirectThreat (SpellEffIndex effIndex);
    void EffectWMODamage (SpellEffIndex effIndex);
    void EffectWMORepair (SpellEffIndex effIndex);
    void EffectWMOChange (SpellEffIndex effIndex);
    void EffectActivateRune (SpellEffIndex effIndex);
    void EffectCreateTamedPet (SpellEffIndex effIndex);
    void EffectDiscoverTaxi (SpellEffIndex effIndex);
    void EffectTitanGrip (SpellEffIndex effIndex);
    void EffectEnchantItemPrismatic (SpellEffIndex effIndex);
    void EffectPlayMusic (SpellEffIndex effIndex);
    void EffectSpecCount (SpellEffIndex effIndex);
    void EffectActivateSpec (SpellEffIndex effIndex);
    void EffectPlayerNotification (SpellEffIndex effIndex);
    void EffectRemoveAura (SpellEffIndex effIndex);
    void EffectCastButtons (SpellEffIndex effIndex);
    void EffectRechargeManaGem (SpellEffIndex effIndex);
    void EffectDamageSelfPct (SpellEffIndex effIndex);

    typedef std::set<Aura *> UsedSpellMods;

    Spell (Unit* Caster, SpellEntry const *info, bool triggered, uint64 originalCasterGUID = 0, bool skipCheck = false);
    ~Spell ();

    void prepare (SpellCastTargets const* targets, AuraEffect const * triggeredByAura = NULL);
    void cancel ();
    void update (uint32 difftime);
    void cast (bool skipCheck = false);
    void finish (bool ok = true);
    void TakePower ();
    void TakeAmmo ();

    void HandleHolyPower (Player* caster);
    void TakeRunePower (bool didHit);
    void TakeReagents ();
    void TakeCastItem ();

    SpellCastResult CheckCast (bool strict);
    SpellCastResult CheckPetCast (Unit* target);

    // handlers
    void handle_immediate ();
    uint64 handle_delayed (uint64 t_offset);
    // handler helpers
    void _handle_immediate_phase ();
    void _handle_finish_phase ();

    SpellCastResult CheckItems ();
    SpellCastResult CheckRange (bool strict);
    SpellCastResult CheckPower ();
    SpellCastResult CheckRuneCost (uint32 runeCostID);
    SpellCastResult CheckCasterAuras () const;

    int32 CalculateDamage (uint8 i, Unit* target)
    {
        return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]);
    }

    bool HaveTargetsForEffect (uint8 effect) const;
    void Delayed ();
    void DelayedChannel ();
    uint32 getState () const
    {
        return m_spellState;
    }
    void setState (uint32 state)
    {
        m_spellState = state;
    }

    void DoCreateItem (uint32 i, uint32 itemtype);
    void WriteSpellGoTargets (WorldPacket * data);
    void WriteAmmoToPacket (WorldPacket * data);

    void SelectSpellTargets ();
    void SelectEffectTargets (uint32 i, uint32 cur);
    void SelectTrajTargets ();

    template<typename T> WorldObject* FindCorpseUsing ();

    bool CheckTarget (Unit* target, uint32 eff);
    bool CanAutoCast (Unit* target);
    void CheckSrc ()
    {
        if (!m_targets.HasSrc())
            m_targets.setSrc(*m_caster);
    }
    void CheckDst ()
    {
        if (!m_targets.HasDst())
            m_targets.setDst(*m_caster);
    }

    static void SendCastResult (Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE);
    void SendCastResult (SpellCastResult result);
    void SendSpellStart ();
    void SendSpellGo ();
    void SendSpellCooldown ();
    void SendLogExecute ();
    void ExecuteLogEffectTakeTargetPower (uint8 effIndex, Unit * target, uint32 powerType, uint32 powerTaken, float gainMultiplier);
    void ExecuteLogEffectExtraAttacks (uint8 effIndex, Unit * victim, uint32 attCount);
    void ExecuteLogEffectInterruptCast (uint8 effIndex, Unit * victim, uint32 spellId);
    void ExecuteLogEffectDurabilityDamage (uint8 effIndex, Unit * victim, uint32 itemslot, uint32 damage);
    void ExecuteLogEffectOpenLock (uint8 effIndex, Object * obj);
    void ExecuteLogEffectCreateItem (uint8 effIndex, uint32 entry);
    void ExecuteLogEffectDestroyItem (uint8 effIndex, uint32 entry);
    void ExecuteLogEffectSummonObject (uint8 effIndex, WorldObject * obj);
    void ExecuteLogEffectUnsummonObject (uint8 effIndex, WorldObject * obj);
    void ExecuteLogEffectResurrect (uint8 effIndex, Unit * target);
    void SendInterrupted (uint8 result);
    void SendChannelUpdate (uint32 time);
    void SendChannelStart (uint32 duration);
    void SendResurrectRequest (Player* target);
    void SendPlaySpellVisual (uint32 SpellID);

    void HandleEffects (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOTarget, uint32 i);
    void HandleThreatSpells (uint32 spellId);

    const SpellEntry * const m_spellInfo;
    Item* m_CastItem;
    uint64 m_castItemGUID;
    uint8 m_cast_count;
    uint32 m_glyphIndex;
    uint32 m_preCastSpell;
    SpellCastTargets m_targets;
    int8 m_comboPointGain;
    SpellCustomErrors m_customError;

    UsedSpellMods m_appliedMods;

    int32 GetCastTime () const
    {
        return m_casttime;
    }
    bool IsAutoRepeat () const
    {
        return m_autoRepeat;
    }
    void SetAutoRepeat (bool rep)
    {
        m_autoRepeat = rep;
    }
    void ReSetTimer ()
    {
        m_timer = m_casttime > 0 ? m_casttime : 0;
    }
    bool IsNextMeleeSwingSpell () const
    {
        return m_spellInfo->Attributes & SPELL_ATTR0_ON_NEXT_SWING;
    }
    bool IsTriggered () const
    {
        return m_IsTriggeredSpell;
    }
    ;
    bool IsChannelActive () const
    {
        return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0;
    }
    bool IsAutoActionResetSpell () const
    {
        return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK);
    }

    bool IsDeletable () const
    {
        return !m_referencedFromCurrentSpell && !m_executedCurrently;
    }
    void SetReferencedFromCurrent (bool yes)
    {
        m_referencedFromCurrentSpell = yes;
    }
    bool IsInterruptable () const
    {
        return !m_executedCurrently;
    }
    void SetExecutedCurrently (bool yes)
    {
        m_executedCurrently = yes;
    }
    uint64 GetDelayStart () const
    {
        return m_delayStart;
    }
    void SetDelayStart (uint64 m_time)
    {
        m_delayStart = m_time;
    }
    uint64 GetDelayMoment () const
    {
        return m_delayMoment;
    }

    bool IsNeedSendToClient () const;

    CurrentSpellTypes GetCurrentContainer ();

    Unit* GetCaster () const
    {
        return m_caster;
    }
    Unit* GetOriginalCaster () const
    {
        return m_originalCaster;
    }
    SpellEntry const * GetSpellInfo () const
    {
        return m_spellInfo;
    }
    int32 GetPowerCost () const
    {
        return m_powerCost;
    }

    void UpdatePointers ();          // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)

    bool CheckTargetCreatureType (Unit* target) const;

    void CleanupTargetList ();

    void SetSpellValue (SpellValueMod mod, int32 value);

    void SetMagnetingAura (Aura* aura)
    {
        m_magnetingAura = aura;
    }

protected:
    void SendLoot (uint64 guid, LootType loottype);

    Unit* const m_caster;

    SpellValue * const m_spellValue;

    uint64 m_originalCasterGUID;          // real source of cast (aura caster/etc), used for spell targets selection
                                          // e.g. damage around area spell trigered by victim aura and damage enemies of aura caster
    Unit* m_originalCaster;          // cached pointer for m_originalCaster, updated at Spell::UpdatePointers()

    Spell** m_selfContainer;          // pointer to our spell container (if applicable)

    //Spell data
    SpellSchoolMask m_spellSchoolMask;          // Spell school (can be overwrite for some spells (wand shoot for example)
    WeaponAttackType m_attackType;          // For weapon based attack
    int32 m_powerCost;          // Calculated spell cost     initialized only in Spell::prepare
    int32 m_casttime;          // Calculated spell cast time initialized only in Spell::prepare
    bool m_canReflect;          // can reflect this spell?
    bool m_autoRepeat;
    uint8 m_runesState;

    uint8 m_delayAtDamageCount;
    bool isDelayableNoMore ()
    {
        if (m_delayAtDamageCount >= 2)
            return true;

        m_delayAtDamageCount++;
        return false;
    }

    // Delayed spells system
    uint64 m_delayStart;          // time of spell delay start, filled by event handler, zero = just started
    uint64 m_delayMoment;          // moment of next delay call, used internally
    bool m_immediateHandled;          // were immediate actions handled? (used by delayed spells only)

    // These vars are used in both delayed spell system and modified immediate spell system
    bool m_referencedFromCurrentSpell;          // mark as references to prevent deleted and access by dead pointers
    bool m_executedCurrently;          // mark as executed to prevent deleted and access by dead pointers
    bool m_needComboPoints;
    uint8 m_applyMultiplierMask;
    float m_damageMultipliers[3];

    // Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS)
    Unit* unitTarget;
    Item* itemTarget;
    GameObject* gameObjTarget;
    int32 damage;
    SpellEffectHandleMode effectHandleMode;
    // used in effects handlers
    Aura * m_spellAura;
    // pointer to magneting aura if spell is redirected
    Aura* m_magnetingAura;

    // this is set in Spell Hit, but used in Apply Aura handler
    DiminishingLevels m_diminishLevel;
    DiminishingGroup m_diminishGroup;

    // -------------------------------------------
    GameObject* focusObject;

    // Damage and healing in effects need just calculate
    int32 m_damage;          // Damage        in effects count here
    int32 m_healing;          // Healing      in effects count here
    int32 m_final_damage;          // Final damage in effects count here

    // ******************************************
    // Spell trigger system
    // ******************************************
    uint32 m_procAttacker;          // Attacker trigger flags
    uint32 m_procVictim;          // Victim   trigger flags
    uint32 m_procEx;
    void prepareDataForTriggerSystem (AuraEffect const * triggeredByAura);

    // *****************************************
    // Spell target subsystem
    // *****************************************
    // Targets store structures and data
    struct TargetInfo
    {
        uint64 targetGUID;
        uint64 timeDelay;
        SpellMissInfo missCondition :8;
        SpellMissInfo reflectResult :8;
        uint8 effectMask :8;
        bool processed :1;
        bool alive :1;
        bool crit :1;
        bool scaleAura :1;
        int32 damage;
    };
    std::list<TargetInfo> m_UniqueTargetInfo;
    uint8 m_channelTargetEffectMask;          // Mask req. alive targets

    struct GOTargetInfo
    {
        uint64 targetGUID;
        uint64 timeDelay;
        uint8 effectMask :8;
        bool processed :1;
    };
    std::list<GOTargetInfo> m_UniqueGOTargetInfo;

    struct ItemTargetInfo
    {
        Item *item;
        uint8 effectMask;
    };
    std::list<ItemTargetInfo> m_UniqueItemInfo;

    void AddUnitTarget (Unit* target, uint32 effIndex);
    void AddUnitTarget (uint64 unitGUID, uint32 effIndex);
    void AddGOTarget (GameObject* target, uint32 effIndex);
    void AddGOTarget (uint64 goGUID, uint32 effIndex);
    void AddItemTarget (Item* target, uint32 effIndex);
    void DoAllEffectOnTarget (TargetInfo *target);
    SpellMissInfo DoSpellHitOnUnit (Unit *unit, uint32 effectMask, bool scaleAura);
    void DoTriggersOnSpellHit (Unit *unit);
    void DoAllEffectOnTarget (GOTargetInfo *target);
    void DoAllEffectOnTarget (ItemTargetInfo *target);
    bool UpdateChanneledTargetList ();
    void SearchAreaTarget (std::list<Unit*> &unitList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
    void SearchGOAreaTarget (std::list<GameObject*> &gobjectList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
    void SearchChainTarget (std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType);
    WorldObject* SearchNearbyTarget (float range, SpellTargets TargetType, SpellEffIndex effIndex);
    bool IsValidSingleTargetEffect (Unit const* target, Targets type) const;
    bool IsValidSingleTargetSpell (Unit const* target) const;
    bool IsValidDeadOrAliveTarget (Unit const* target) const;
    void CalculateDamageDoneForAllTargets ();
    int32 CalculateDamageDone (Unit *unit, const uint32 effectMask, float *multiplier);
    void SpellDamageSchoolDmg (SpellEffIndex effIndex);
    void SpellDamageWeaponDmg (SpellEffIndex effIndex);
    void SpellDamageHeal (SpellEffIndex effIndex);

    void PrepareTargetProcessing ();
    void FinishTargetProcessing ();

    // spell execution log
    void InitEffectExecuteData (uint8 effIndex);
    void CleanupEffectExecuteData ();
    void CheckEffectExecuteData ();

    // Scripting system
    void LoadScripts ();
    SpellCastResult CallScriptCheckCastHandlers ();
    void PrepareScriptHitHandlers ();
    bool CallScriptEffectHandlers (SpellEffIndex effIndex);
    void CallScriptBeforeHitHandlers ();
    void CallScriptOnHitHandlers ();
    void CallScriptAfterHitHandlers ();
    void CallScriptAfterUnitTargetSelectHandlers (std::list<Unit*>& unitTargets, SpellEffIndex effIndex);
    std::list<SpellScript *> m_loadedScripts;

    // effect helpers
    void GetSummonPosition (uint32 i, Position &pos, float radius = 0.0f, uint32 count = 0);
    void SummonGuardian (uint32 i, uint32 entry, SummonPropertiesEntry const *properties);
    void CalculateJumpSpeeds (uint8 i, float dist, float & speedxy, float & speedz);

    SpellCastResult CanOpenLock (uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
    // -------------------------------------------

    //List For Triggered Spells
    typedef std::vector<std::pair<SpellEntry const*, int32> > ChanceTriggerSpells;
    ChanceTriggerSpells m_ChanceTriggerSpells;

    uint32 m_spellState;
    int32 m_timer;

    TriggerCastFlags _triggeredCastFlags;

    bool m_IsTriggeredSpell;

    // if need this can be replaced by Aura copy
    // we can't store original aura link to prevent access to deleted auras
    // and in same time need aura data and after aura deleting.
    SpellEntry const* m_triggeredByAuraSpell;

    uint32 m_customAttr;
    bool m_skipCheck;
    uint32 m_effectMask;
    uint8 m_auraScaleMask;

    ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS];

#ifdef MAP_BASED_RAND_GEN
    int32 irand(int32 min, int32 max)
    {   return int32 (m_caster->GetMap()->mtRand.randInt(max - min)) + min;}
    uint32 urand(uint32 min, uint32 max)
    {   return m_caster->GetMap()->mtRand.randInt(max - min) + min;}
    int32 rand32()
    {   return m_caster->GetMap()->mtRand.randInt();}
    double rand_norm()
    {   return m_caster->GetMap()->mtRand.randExc();}
    double rand_chance()
    {   return m_caster->GetMap()->mtRand.randExc(100.0);}
#endif
};

namespace Trinity
{
    struct SpellNotifierCreatureAndPlayer
    {
        std::list<Unit*> *i_data;
        SpellNotifyPushType i_push_type;
        float i_radius;
        SpellTargets i_TargetType;
        const Unit * const i_source;
        uint32 i_entry;
        const Position * const i_pos;
        bool i_requireDeadTarget;

        SpellNotifierCreatureAndPlayer (Unit *source, std::list<Unit*> &data, float radius, SpellNotifyPushType type, SpellTargets TargetType = SPELL_TARGETS_ENEMY, const Position *pos = NULL, uint32 entry = 0, bool requireDeadTarget = false) :
                i_data(&data), i_push_type(type), i_radius(radius), i_TargetType(TargetType), i_source(source), i_entry(entry), i_pos(pos), i_requireDeadTarget(requireDeadTarget)
        {
            ASSERT(i_source);
        }

        template<class T> inline void Visit (GridRefManager<T> &m)
        {
            for (typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr)
            {
                Unit *target = (Unit*) itr->getSource();

                if (!i_source->canSeeOrDetect(target, true))
                    continue;

                switch (i_TargetType)
                {
                case SPELL_TARGETS_ENEMY:
                    if (target->isTotem())
                        continue;
                    if (!target->isAttackableByAOE(i_requireDeadTarget))
                        continue;
                    if (i_source->IsControlledByPlayer())
                    {
                        if (i_source->IsFriendlyTo(target))
                            continue;
                    }
                    else
                    {
                        if (!i_source->IsHostileTo(target))
                            continue;
                    }
                    break;
                case SPELL_TARGETS_ALLY:
                    if (target->isTotem())
                        continue;
                    if (!i_source->IsFriendlyTo(target))
                        continue;
                    if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
                        continue;
                    if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->isGameMaster())
                        continue;
                    if (target->isAlive() == i_requireDeadTarget)
                        continue;
                    break;
                case SPELL_TARGETS_ENTRY:
                    if (target->GetEntry() != i_entry)
                        continue;
                    break;
                case SPELL_TARGETS_ANY:
                default:
                    break;
                }

                switch (i_push_type)
                {
                case PUSH_SRC_CENTER:
                case PUSH_DST_CENTER:
                case PUSH_CHAIN:
                default:
                    if (target->IsWithinDist3d(i_pos, i_radius))
                        i_data->push_back(target);
                    break;
                case PUSH_IN_FRONT:
                    if (i_source->isInFront(target, i_radius, static_cast<float>(M_PI / 2)))
                        i_data->push_back(target);
                    break;
                case PUSH_IN_BACK:
                    if (i_source->isInBack(target, i_radius, static_cast<float>(M_PI / 2)))
                        i_data->push_back(target);
                    break;
                case PUSH_IN_LINE:
                    if (i_source->HasInLine(target, i_radius, i_source->GetObjectSize()))
                        i_data->push_back(target);
                    break;
                case PUSH_IN_THIN_LINE:          // only traj
                    if (i_pos->HasInLine(target, i_radius, 0))
                        i_data->push_back(target);
                    break;
                }
            }
        }

#ifdef _WIN32
        template<> inline void Visit(CorpseMapType &)
        {}
        template<> inline void Visit(GameObjectMapType &)
        {}
        template<> inline void Visit(DynamicObjectMapType &)
        {}
#endif
    };

#ifndef _WIN32
    template<> inline void SpellNotifierCreatureAndPlayer::Visit (CorpseMapType&)
    {
    }
    template<> inline void SpellNotifierCreatureAndPlayer::Visit (GameObjectMapType&)
    {
    }
    template<> inline void SpellNotifierCreatureAndPlayer::Visit (DynamicObjectMapType&)
    {
    }
#endif
}

typedef void (Spell::*pEffect) (SpellEffIndex effIndex);

class SpellEvent: public BasicEvent
{
public:
    SpellEvent (Spell* spell);
    virtual ~SpellEvent ();

    virtual bool Execute (uint64 e_time, uint32 p_time);
    virtual void Abort (uint64 e_time);
    virtual bool IsDeletable () const;
protected:
    Spell* m_Spell;
};
#endif
